from datetime import datetime

from django.db import IntegrityError
from django.utils import timezone
from rest_framework import serializers
from rest_framework.permissions import AllowAny
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

from Submission.serializers import SubmissionListSerializer
from .models import Person, PersonDetail, RejesterCode


class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = (
            'id',
            'username',
            'password',
            'email',
            'ban',
            'is_active',
            'is_staff',
            'is_superuser',
        )
        read_only_fields = ('id',)


class PersonRegisterSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = (
            'username',
            'password',
            'email',
            'is_staff',
        )
        extra_kwargs = {"password": {"write_only": True}}

    username = serializers.CharField()
    password = serializers.CharField()
    email = serializers.EmailField()

    def save(self, **kwargs):
        email = self.validated_data['email']
        password = self.validated_data['password']
        username = self.validated_data['username']
        is_staff = False

        try:
            if is_staff:
                person = Person.objects.create_user(username=username,
                                                    password=password,
                                                    is_active=True,
                                                    is_staff=False,
                                                    is_superuser=False,
                                                    email=email)
            else:
                person = Person.objects.create_superuser(username=username,
                                                         password=password,
                                                         email=email,
                                                         )
            return person
        except IntegrityError as e:
            if 'username' in str(e):  # 检查异常信息是否与用户名有关
                raise serializers.ValidationError("该用户名已被注册")
            elif 'email' in str(e):  # 检查异常信息是否与邮箱有关
                raise serializers.ValidationError("该邮箱已被注册")
            else:
                raise serializers.ValidationError("未知错误:" + str(e))


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    """
    一个用于获取用户标识符、用户名和电子邮件并将其包含在生成的JWT令牌内的类。
    """
    permission_classes = (AllowAny,)
    # 定义要添加到token中的字段名称，以便于维护和修改
    ADDITIONAL_TOKEN_FIELDS = {'id', 'username', 'email', 'is_staff'}

    @classmethod
    def get_token(cls, person):
        """
        获得一个包含用户id、用户名和电子邮件的JWT令牌。

        参数:
            person: 一个具有id、username和email属性的用户对象。

        返回:
            一个包含JWT令牌信息的字典。
        """
        try:
            token = super().get_token(person)

            # 检查person对象是否具有所有必要的属性
            for field in cls.ADDITIONAL_TOKEN_FIELDS:
                if not hasattr(person, field):
                    raise ValueError(f"person对象缺少必要的属性: {field}")

                # 安全地添加额外的信息到token中
                token[field] = getattr(person, field)

            return token
        except Exception as e:
            # 处理可能的异常，例如日志记录、错误回报等
            # 这里只是简单打印异常，实际应用中可能需要更复杂的处理逻辑
            print(f"获取token时发生异常：{e}")
            raise e

    def validate(self, attrs):
        """
        此方法为响应数据结构处理
        原有的响应数据结构无法满足需求，在这里重写结构如下：
        {
            "refresh": "xxxx.xxxxx.xxxxx",
            "token": "xxxx.xxxx.xxxx",
            "expire": Token有效期截止时间,
            "username": "用户名",                                        
            "email": "邮箱"
        }

        :param attrs: 請求參數
        :return: 响应数据
        """
        # data是个字典
        # 其结构为：{'refresh': '用于刷新token的令牌', 'token': '用于身份验证的Token值'}
        username = attrs.get("username")
        person = Person.objects.filter(email=username).first()
        if person is not None:
            attrs['username'] = person.username
        data = super().validate(attrs)

        if person is None:
            person = Person.objects.filter(username=username).first()
        person.last_login = datetime.now()
        person.save(update_fields=['last_login'])

        # 获取Token对象
        refresh = self.get_token(self.user)
        # 令牌到期时间
        data['expire'] = datetime.fromtimestamp(refresh.access_token.payload['exp']).strftime(
            '%Y-%m-%d %H:%M:%S')  # 有效期

        # 修改 token 的键名
        data['token'] = data.pop('access')

        # 用户名
        data['username'] = self.user.username
        # 邮箱
        data['email'] = self.user.email
        data['id'] = self.user.id
        data['role'] = self.user.is_staff

        try:
            data['avatar'] = self.user.detail.profile_picture.url
        except:
            data['avatar'] = None

        return data


class PersonDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = PersonDetail
        fields = '__all__'


class GetPersonDetail(serializers.ModelSerializer):
    detail = PersonDetailSerializer()
    submissions = SubmissionListSerializer(source="user_submissions", many=True)

    class Meta:
        model = Person
        fields = (
            'username',
            'last_login',
            'detail',
            'submissions',
        )

    def create(self, validated_data):
        detail_data = validated_data.pop('detail')
        person = Person.objects.create(**detail_data)
        PersonDetail.objects.create(person=person, **validated_data)
        return person


class CommonUserRegisterSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = (
            'username',
            'password',
            'email',
            'code',
        )

    username = serializers.CharField()
    email = serializers.EmailField()
    password = serializers.CharField()
    code = serializers.CharField(max_length=10, required=True, write_only=True, error_messages={
        'required': '验证码不能为空',
    })

    def save(self, **kwargs):
        email = self.validated_data['email']
        password = self.validated_data['password']
        username = self.validated_data['username']
        code = self.validated_data['code']

        validate_code = RejesterCode.objects.filter(email=email, is_active=True).first()
        if validate_code is None or validate_code.verification_code != code:
            raise serializers.ValidationError("验证码错误")
        # 判断当前的验证码是否已经超时
        if validate_code.expires < datetime.now():
            raise serializers.ValidationError("验证码已过期")

        try:
            person = Person.objects.create_user(username=username,
                                                password=password,
                                                email=email)
            return person
        except IntegrityError as e:
            if 'username' in str(e):  # 检查异常信息是否与用户名有关
                raise serializers.ValidationError("该用户名已被注册")
            elif 'email' in str(e):  # 检查异常信息是否与邮箱有关
                raise serializers.ValidationError("该邮箱已被注册")
            else:
                raise serializers.ValidationError("未知错误:" + str(e))


class ClockinSerializer(serializers.ModelSerializer):
    last_clockin = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
    luck = serializers.IntegerField()
    username = serializers.CharField(source="person.username", read_only=True)

    class Meta:
        model = PersonDetail
        fields = (
            'username',
            'luck',
            'last_clockin',
        )

    def validate_last_clockin(self, value):
        today = timezone.now().date()
        if value and value.date() == today:
            raise serializers.ValidationError("今天已经签到过了")
        return value


class PersonAdminListSerializer(serializers.ModelSerializer):
    registerTime = serializers.DateTimeField(source="create_time")
    loginTime = serializers.DateTimeField(source="last_login")

    class Meta:
        model = Person
        fields = (
            'id',
            'email',
            'registerTime',
            'loginTime',
            'username',
        )

    def get_loginTime(self, obj):
        if obj.last_login is None:
            return "null"  # 或者返回 ""，根据您的需求调整
        return obj.last_login


class PersonRankSerializer(serializers.ModelSerializer):
    errorSubmit = serializers.SerializerMethodField()
    percent = serializers.SerializerMethodField()
    totalSubmit = serializers.IntegerField(source='total_submitted')
    successSubmit = serializers.IntegerField(source='total_accepted')

    class Meta:
        model = Person
        fields = (
            'id',
            'username',
            'totalSubmit',
            'successSubmit',
            'percent',
            'errorSubmit',
        )

    def get_errorSubmit(self, obj):
        return obj.total_submitted - obj.total_accepted

    def get_percent(self, obj):
        try:
            return obj.total_accepted / obj.total_submitted
        except ZeroDivisionError:
            return 0
